typedef struct XsHandle {
PyObject_HEAD;
struct xs_handle *xh;
+ PyObject *watches;
} XsHandle;
static inline struct xs_handle *xshandle(PyObject *self)
"Raises RuntimeError on error.\n" \
"\n"
+/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
+#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
+
static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", "token", NULL };
- static char *arg_spec = "s|is";
+ static char *arg_spec = "sO";
char *path = NULL;
- char *token = "";
+ PyObject *token;
+ char token_str[MAX_STRLEN(unsigned long) + 1];
+ int i;
+ XsHandle *xsh = (XsHandle *)self;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&path, &token))
goto exit;
- xsval = xs_watch(xh, path, token);
+ Py_INCREF(token);
+ sprintf(token_str, "%li", (unsigned long)token);
+ xsval = xs_watch(xh, path, token_str);
val = pyvalue_int(xsval);
+ if (xsval) {
+ for (i = 0; i < PyList_Size(xsh->watches); i++) {
+ if (PyList_GetItem(xsh->watches, i) == Py_None) {
+ PyList_SetItem(xsh->watches, i, token);
+ break;
+ }
+ }
+ if (i == PyList_Size(xsh->watches))
+ PyList_Append(xsh->watches, token);
+ } else
+ Py_DECREF(token);
exit:
return val;
}
static char *kwd_spec[] = { NULL };
static char *arg_spec = "";
+ XsHandle *xsh = (XsHandle *)self;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
char **xsval = NULL;
+ PyObject *token;
+ int i;
if (!xh)
goto exit;
goto exit;
xsval = xs_read_watch(xh);
if (!xsval) {
- val = PyErr_SetFromErrno(PyExc_RuntimeError);
- goto exit;
+ val = PyErr_SetFromErrno(PyExc_RuntimeError);
+ goto exit;
+ }
+ if (sscanf(xsval[1], "%li", (unsigned long *)&token) != 1) {
+ PyErr_SetString(PyExc_RuntimeError, "invalid token");
+ goto exit;
+ }
+ for (i = 0; i < PyList_Size(xsh->watches); i++) {
+ if (token == PyList_GetItem(xsh->watches, i))
+ break;
+ }
+ if (i == PyList_Size(xsh->watches)) {
+ PyErr_SetString(PyExc_RuntimeError, "invalid token");
+ goto exit;
}
/* Create tuple (path, token). */
- val = Py_BuildValue("(ss)", xsval[0], xsval[1]);
+ val = Py_BuildValue("(sO)", xsval[0], token);
exit:
if (xsval)
free(xsval);
PyObject *kwds)
{
static char *kwd_spec[] = { "token", NULL };
- static char *arg_spec = "s";
- char *token;
+ static char *arg_spec = "O";
+ PyObject *token;
+ char token_str[MAX_STRLEN(unsigned long) + 1];
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &token))
goto exit;
- xsval = xs_acknowledge_watch(xh, token);
+ sprintf(token_str, "%li", (unsigned long)token);
+ xsval = xs_acknowledge_watch(xh, token_str);
val = pyvalue_int(xsval);
exit:
return val;
static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", "token", NULL };
- static char *arg_spec = "s|s";
+ static char *arg_spec = "sO";
char *path = NULL;
- char *token = "";
+ PyObject *token;
+ char token_str[MAX_STRLEN(unsigned long) + 1];
+ int i;
+ XsHandle *xsh = (XsHandle *)self;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path,
&token))
goto exit;
- xsval = xs_unwatch(xh, path, token);
+ sprintf(token_str, "%li", (unsigned long)token);
+ xsval = xs_unwatch(xh, path, token_str);
val = pyvalue_int(xsval);
+ for (i = 0; i < PyList_Size(xsh->watches); i++) {
+ if (token == PyList_GetItem(xsh->watches, i)) {
+ Py_INCREF(Py_None);
+ PyList_SetItem(xsh->watches, i, Py_None);
+ break;
+ }
+ }
exit:
return val;
}
{
static char *kwd_spec[] = { NULL };
static char *arg_spec = "";
+ int i;
+ XsHandle *xsh = (XsHandle *)self;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 1;
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
+ for (i = 0; i < PyList_Size(xsh->watches); i++) {
+ /* TODO: xs_unwatch watches */
+ Py_INCREF(Py_None);
+ PyList_SetItem(xsh->watches, i, Py_None);
+ }
xs_daemon_close(xh);
- ((XsHandle*)self)->xh = NULL;
+ xsh->xh = NULL;
val = pyvalue_int(xsval);
exit:
return val;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&readonly))
- goto exit;
+ return NULL;
xsh = PyObject_New(XsHandle, &xshandle_type);
if (!xsh)
+ return NULL;
+ xsh->watches = PyList_New(0);
+ if (!xsh->watches)
goto exit;
xsh->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open());
if (!xsh->xh) {
- PyObject_Del(xsh);
- val = pyvalue_int(0);
+ Py_DECREF(xsh->watches);
goto exit;
}
val = (PyObject *)xsh;
- exit:
return val;
+ exit:
+ PyObject_Del(xsh);
+ return NULL;
}
static PyMethodDef xs_methods[] = {
--- /dev/null
+
+import select
+import threading
+from xen.lowlevel import xs
+
+class xswatch:
+
+ watchThread = None
+ threadcond = threading.Condition()
+ xs = None
+ xslock = threading.Lock()
+ watches = []
+
+ def __init__(self, path, fn, args=(), kwargs={}):
+ self.fn = fn
+ self.args = args
+ self.kwargs = kwargs
+ xswatch.watchStart()
+ xswatch.xslock.acquire()
+ xswatch.xs.watch(path, self)
+ xswatch.xslock.release()
+ xswatch.watches.append(self)
+
+ def watchStart(cls):
+ cls.threadcond.acquire()
+ if cls.watchThread:
+ cls.threadcond.release()
+ return
+ cls.watchThread = threading.Thread(name="Watcher",
+ target=cls.watchMain)
+ cls.watchThread.setDaemon(True)
+ cls.watchThread.start()
+ while cls.xs == None:
+ cls.threadcond.wait()
+ cls.threadcond.release()
+
+ watchStart = classmethod(watchStart)
+
+ def watchMain(cls):
+ cls.threadcond.acquire()
+ cls.xs = xs.open()
+ cls.threadcond.notifyAll()
+ cls.threadcond.release()
+ while True:
+ try:
+ (ord, owr, oer) = select.select([ cls.xs ], [], [])
+ cls.xslock.acquire()
+ # reconfirm ready to read with lock
+ (ord, owr, oer) = select.select([ cls.xs ], [], [], 0.001)
+ if not cls.xs in ord:
+ cls.xslock.release()
+ continue
+ we = cls.xs.read_watch()
+ watch = we[1]
+ cls.xs.acknowledge_watch(watch)
+ cls.xslock.release()
+ except RuntimeError, ex:
+ print ex
+ raise
+ watch.fn(*watch.args, **watch.kwargs)
+
+ watchMain = classmethod(watchMain)